package com.henu.cee_service.service.impl;

import com.github.pagehelper.PageHelper;
import com.henu.cee_service.constants.Constant;
import com.henu.cee_service.entity.User;
import com.henu.cee_service.exception.BusinessException;
import com.henu.cee_service.exception.code.BaseResponseCode;
import com.henu.cee_service.mapper.UserMapper;
import com.henu.cee_service.service.RedisService;
import com.henu.cee_service.service.UserService;
import com.henu.cee_service.utils.JwtTokenUtil;
import com.henu.cee_service.utils.PageUtil;
import com.henu.cee_service.utils.PasswordUtils;
import com.henu.cee_service.vo.req.LoginReqVO;
import com.henu.cee_service.vo.req.RegisterReqVO;
import com.henu.cee_service.vo.req.UserPageReqVO;
import com.henu.cee_service.vo.resq.LoginRespVO;
import com.henu.cee_service.vo.resq.PageVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * description: UserServiceImpl <br>
 * date: 2020/2/28 16:16 <br>
 * author: JSM <br>
 * version: 1.0 <br>
 */

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisService redisService;

    @Override
    public LoginRespVO login(LoginReqVO vo) {
        User userInfo = userMapper.selectByEmail(vo.getEmail());
        if (userInfo == null) {
            throw new BusinessException(BaseResponseCode.ACCOUNT_ERROR);
        } else if (userInfo.getStatus() == 2) {
            throw new BusinessException(BaseResponseCode.ACCOUNT_LOCK);
        }
        if (!PasswordUtils.matches(userInfo.getSalt(),  vo.getPassword(), userInfo.getPassword())) {
            throw new BusinessException(BaseResponseCode.ACCOUNT_PASSWORD_ERROR);
        }
        LoginRespVO loginRespVO = new LoginRespVO();
        loginRespVO.setPhone(userInfo.getPhone());
        loginRespVO.setUsername(userInfo.getUsername());
        loginRespVO.setId(userInfo.getId());
        Map<String, Object> claims = new HashMap<>();
        claims.put(Constant.JWT_ROLES_KEY, getRolesByUserId(userInfo.getId()));
        claims.put(Constant.JWT_PERMISSIONS_KEY,getPermissionsByUserId(userInfo.getId()));
        claims.put(Constant.JWT_USER_NAME,userInfo.getUsername());
        String accessToken = JwtTokenUtil.getAccessToken(userInfo.getId(), claims);
        String refreshToken;
        if (vo.getType().equals("1")) {
            refreshToken = JwtTokenUtil.getRefreshToken(userInfo.getId(), claims);
        } else {
            refreshToken = JwtTokenUtil.getRefreshAppToken(userInfo.getId(), claims);
        }
        loginRespVO.setAccessToken(accessToken);
        loginRespVO.setRefreshToken(refreshToken);
        return loginRespVO;
    }

    @Override
    public String register(RegisterReqVO vo) {
        User userT = userMapper.selectByEmail(vo.getEmail());
        if (userT != null) {
            throw new BusinessException(BaseResponseCode.ACCOUNT_EXIST);
        } else {
            User user = new User();
            BeanUtils.copyProperties(vo, user);
            user.setCreateTime(new Date());
            user.setId(UUID.randomUUID().toString());
            String salt = PasswordUtils.getSalt();
            String encode = PasswordUtils.encode(vo.getPassword(), salt);
            user.setSalt(salt);
            user.setPassword(encode);
            int i = userMapper.insertSelective(user);
            if (i != 1) {
                throw new BusinessException(BaseResponseCode.SYSTEM_ERROR);
            } else {
                return "注册成功";
            }
        }

    }

    @Override
    public void logout(String accessToken, String refreshToken) {
        if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(refreshToken)) {
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        Subject subject = SecurityUtils.getSubject();
        log.info("subject.getPrincipals()={}",subject.getPrincipals());
        if (subject.isAuthenticated()) {
            subject.logout();
        }
        String userId=JwtTokenUtil.getUserId(accessToken);
        /**
         * 把token 加入黑名单 禁止再登录
         */
        redisService.set(Constant.JWT_REFRESH_TOKEN_BLACKLIST+accessToken,userId,JwtTokenUtil.getRemainingTime(accessToken), TimeUnit.MILLISECONDS);
        /**
         * 把 refreshToken 加入黑名单 禁止再拿来刷新token
         */
        redisService.set(Constant.JWT_REFRESH_TOKEN_BLACKLIST+refreshToken,userId,JwtTokenUtil.getRemainingTime(refreshToken),TimeUnit.MILLISECONDS);

    }

    @Override
    public PageVO<User> pageInfo(UserPageReqVO vo) {
        PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
        List<User> list=userMapper.seletAll(vo);
        return PageUtil.getPageVO(list);
    }

    /**
     * mock 数据
     * 通过用户id获取该用户所拥有的角色
     * 后期修改为通过操作DB获取
     * @Author:      JSM
     * @UpdateUser:
     * @Version:     0.0.1
     * @param userId
     * @return       java.util.List<java.lang.String>
     * @throws
     */
    private List<String> getRolesByUserId(String userId){

        List<String> roles=new ArrayList<>();
        if("9a26f5f1-cbd2-473d-82db-1d6dcf4598f8".equals(userId)){
            roles.add("admin");
        }else {
            roles.add("test");
        }
        return roles;
    }
    /**
     * mock 数据
     * 通过用户id获取该用户所拥有的角色
     * 后期通过操作数据获取
     * @Author:      JSM
     * @UpdateUser:
     * @Version:     0.0.1
     * @param userId
     * @return       java.util.List<java.lang.String>
     * @throws
     */
    private List<String> getPermissionsByUserId(String userId){
        List<String> permissions=new ArrayList<>();
        if("9a26f5f1-cbd2-473d-82db-1d6dcf4598f8".equals(userId)){
            permissions.add("sys:user:list");
            permissions.add("sys:user:add");
            permissions.add("sys:user:update");
            permissions.add("sys:user:detail");
        }else {
            permissions.add("sys:user:detail");
        }
        return permissions;
    }

}
